package com.firemoss.atonement.test.entitymanager
{
	import com.firemoss.atonement.entitymanager.EntityManager;
	import com.firemoss.atonement.entitymanager.IEntityManager;
	import com.firemoss.atonement.test.entitymanager.objects.AggregatedEntity;
	import com.firemoss.atonement.test.entitymanager.objects.TestEntity;
	import com.firemoss.atonement.test.mapper.objects.Address;
	import com.firemoss.atonement.test.mapper.objects.Contact;
	import com.firemoss.atonement.test.metadata.inspectors.entity.impl.CacheManagementStrategyImpl;
	
	import flash.utils.Dictionary;
	
	import mx.collections.ArrayCollection;
	import mx.collections.ListCollectionView;
	import mx.utils.UIDUtil;
	
	import org.flexunit.asserts.*;

	public class EntityManagerTests
	{		
		// Needed for some instantiations by name...
		public var foo : ListCollectionView = new ListCollectionView()
			
		private var em : IEntityManager
			
		[Before]
		public function setUp():void
		{
			em = new EntityManager()
		}

		[Test]
		public function em_puts_and_gets_same_instance_on_first_put() : void
		{
			var put : TestEntity = new TestEntity()
			put.id = this
				
			em.put( put )
			var gotten : TestEntity = em.get( TestEntity, this ) as TestEntity
			
			assertEquals( put, gotten )
		}
		
		[Test]
		public function em_can_get_by_entity_name() : void
		{
			var put : TestEntity = new TestEntity()
			put.id = this
			
			em.put( put )
			var gotten : TestEntity = em.getByName( "TestEntity", this ) as TestEntity
			
			assertEquals( put, gotten )
		}
		
		[Test]
		public function em_updates_on_second_put() : void
		{
			var put : TestEntity = new TestEntity()
			put.id = this
			put.somethingElse = "original"
				
			var update : TestEntity = new TestEntity()
			update.id = this
			update.somethingElse = "updated"
			
			em.put( put )
			var gotten : TestEntity = em.get( TestEntity, this ) as TestEntity
			
			assertEquals( put, gotten )
			
			em.put( update )
			var gottenAgain : TestEntity = em.get( TestEntity, this ) as TestEntity
			
			assertFalse( "On second got, got the update instance!", gottenAgain == update )
			assertEquals( gottenAgain, put )
			assertTrue( "'somethingElse' property's value wasn't updated!", update.somethingElse == put.somethingElse )
		}
		
		
		[Test]
		public function dictionaries_are_cacheable() : void
		{
			var dict : Dictionary = new Dictionary()
			var ent : TestEntity = new TestEntity()
			var aggEnt : AggregatedEntity = new AggregatedEntity()
			
			ent.id = this
			aggEnt.id = this
			dict[ this ] = aggEnt
			ent.dict = dict
				
			em.put( ent )
				
			var gotten : TestEntity = em.get( TestEntity, this ) as TestEntity
			assertEquals( gotten, ent )
			var gottenAggEnt : AggregatedEntity = em.get( AggregatedEntity, this ) as AggregatedEntity
			assertNotNull( gottenAggEnt )
			assertEquals( gottenAggEnt, aggEnt )
		}
		
		[Test]
		public function collections_are_cacheable() : void
		{
			var col : ArrayCollection = new ArrayCollection()
			var ent : TestEntity = new TestEntity()
			var aggEnt : AggregatedEntity = new AggregatedEntity()
			
			ent.id = this
			aggEnt.id = this
			col.addItem( aggEnt )
			ent.collection = col
			
			em.put( ent )
			
			var gotten : TestEntity = em.get( TestEntity, this ) as TestEntity
			assertEquals( gotten, ent )
			var gottenAggEnt : AggregatedEntity = em.get( AggregatedEntity, this ) as AggregatedEntity
			assertNotNull( gottenAggEnt )
			assertEquals( gottenAggEnt, aggEnt )
		}
		
		[Test]
		public function singular_relationships_are_mapped_into_the_manager() : void
		{
			var address : Address = new Address({ id : "address", line1 : "primLine1" })
			var contact : Contact = new Contact({ id : "contact", primaryAddress : address })
				
			em.put( contact )
				
			assertNotNull( em.get( Contact, "contact" ), "contact was null" )
			assertNotNull( em.get( Address, "address" ), "address was null" )
		}
		
		[Test]
		public function simple_type_collections_can_be_put_into_the_manager() : void
		{
			var contact : Contact = new Contact({ id : "contact", stringArray : [ "Foo", "Bar"] })
			
			em.put( contact )
			
			var gotten : Contact = em.get( Contact, "contact" ) as Contact
			assertNotNull( gotten, "contact was null" )
			assertTrue( gotten.stringArray.length == 2 )
			assertTrue( gotten.stringArray[1] == "Bar" )
			
			var update: Contact = new Contact({ id : "contact", stringArray : [ "Foo", "Bar2", "Whee"] })
			em.put( update )
				
			assertTrue( gotten.stringArray.length == 3 )
			assertTrue( gotten.stringArray[1] == "Bar2" )
			assertTrue( gotten.stringArray[2] == "Whee" )
		}
		
		[Test]
		public function can_get_by_example_even_when_example_is_different_instance_with_same_id() : void
		{
			var entity : TestEntity = new TestEntity()
			var example : TestEntity = new TestEntity()
				
			entity.id = UIDUtil.createUID()
			example.id = entity.id
				
			em.put( entity )
				
			assertEquals( em.getByExample( example ), entity );
			assertFalse( em.getByExample( example ) == example );
		}
		
		[Test]
		public function lists_are_put_with_updates_and_inserts_recognized_and_members_resolved_accordingly() : void
		{
			var updatedEntity : TestEntity = new TestEntity()
			var insertedEntity : TestEntity = new TestEntity()
			var mergedEntity : TestEntity = new TestEntity()
			var list = new ArrayCollection( [ insertedEntity, mergedEntity ] )
				
			// We'll put this entity into the EntityManager directly
			updatedEntity.id = UIDUtil.createUID()
			updatedEntity.somethingElse = "originalValue"
				
			// We'll put this entity into the list, then put the list into the EntityManager
			insertedEntity.id = UIDUtil.createUID()
			
			/*
				We'll put this entity ito the list, then put the list into the EntityManager: because it has
				the same id value as updatedEntity, it should actually update the state of updatedEntity
				and cause the lists's contents to be updated to have a reference to updatedEntity, not mergedEntity
			*/
			mergedEntity.id = updatedEntity.id
			mergedEntity.somethingElse = "updatedValue"
			
			// Direct put of updatedEntity
			em.put( updatedEntity )
				
			// Now put the list
			em.putList( list )
				
			// updatedEntity should now be in the cache
			assertEquals( em.get( TestEntity, updatedEntity.id ), updatedEntity );
			
			// mergedEntity should _not_ be in the cache: it should've updated updatedEntity
			assertFalse( em.get( TestEntity, mergedEntity.id ) == mergedEntity );
			
			// updatedEntity should be in the cache and should've had its properties updated from values on mergedEntity
			assertEquals( em.get( TestEntity, mergedEntity.id ), updatedEntity );
			assertEquals( TestEntity( em.get( TestEntity, mergedEntity.id ) ).somethingElse, "updatedValue" );
			
			// the list should not contain mergedEntity: it should've been replaced by the original updatedEntity
			assertFalse( list.contains( mergedEntity ) );
			assertTrue( list.contains( updatedEntity ) );
			assertTrue( list.contains( insertedEntity ) );
		}

	}
}